#include "seaory_adaptor.h"
#include "SeaoryPrinter.h"

using namespace std;

namespace SwanLink {
namespace Finance {
#define ErrCheck(ret) do {\
    if (ret != 0) {\
        int result = TransformResultCode(__func__ , ret);\
        return result;\
    }\
}while(0)

#define CheckCall(func) do {\
    uint32_t ret = func;\
    if (ret != 0) {\
        int result = TransformResultCode(#func , ret);\
        return result;\
    }\
}while(0)

IMakeCardSeaoryAdaptor::IMakeCardSeaoryAdaptor():isOpen(false) {
    memset_s(usbPort, 128, 0, 128);
}

IMakeCardSeaoryAdaptor::~IMakeCardSeaoryAdaptor() {}

int IMakeCardSeaoryAdaptor::Open(const Transport &trans)
{
    if (AM_USB != trans.mode) {
        MAKECARD_HILOGE(MAKECARD_SRV,
                       "open failed,seaory makecard only supports usb port");
        return ERR_TRANS_PARAM_ERROR;
    }
    if ("" == std::string(trans.dev)) {
        MAKECARD_HILOGE(MAKECARD_SRV, "param tran port was null");
        return ERR_TRANS_PARAM_ERROR;
    }
    char infoValue[32];
    uint32_t libResult = SOY_PR_GetPrinterInfo(trans.dev,
                                                INFO_MODEL_NAME,
                                                infoValue);
    int result = TransformResultCode("Open", libResult);
    if (result == SUCCESS) {
        if (isOpen) {
            return ERR_DEVICE_OPEN_ALREADY;
        } else {
            isOpen = true;
            strcpy_s(usbPort, MAX_DEV_NAME_LEN, trans.dev);
        }
    }
    return result;
}

int IMakeCardSeaoryAdaptor::Close()
{
    if (isOpen == false) {
        MAKECARD_HILOGE(MAKECARD_SRV, "device was not open");
        return ERR_DEVICE_NOT_OPEN;
    }
    int result = GetStatus();
    if (result == ERR_DEVICE_NOT_EXIST) {
        return ERR_DEVICE_DISCONNECT;
    }
    if (result != SUCCESS) {
        return result;
    }
    isOpen = false;
    memset_s(usbPort, 128, 0, 128);
    return result;
}

bool IMakeCardSeaoryAdaptor::IsOpen()
{
    if (!isOpen) {
        return false;
    }
    int result = GetStatus();
    if (result == ERR_DEVICE_NOT_EXIST) {
        return false;
    }
    return true;
}

int IMakeCardSeaoryAdaptor::GetStatus()
{
    uint32_t status = 1;  // Incorrect function
    SOY_PR_GetPrinterStatus(usbPort, &status);
    int result = TransformResultCode("get status", status);
    return result;
}

int IMakeCardSeaoryAdaptor::GetStatus(int /*module*/, char* err)
{
    if (isOpen == false) {
        MAKECARD_HILOGE(MAKECARD_SRV, "device was not open");
        return ERR_DEVICE_NOT_OPEN;
    }
    if (err == nullptr) {
        MAKECARD_HILOGE(MAKECARD_SRV, "param err was null");
        return ERR_TRANS_PARAM_ERROR;
    }
    uint32_t status = ERROR;
    SOY_PR_GetPrinterStatus(usbPort, &status);
    int result = TransformResultCode("get status", status);
    if (result == ERR_DEVICE_NOT_EXIST) {
        return ERR_DEVICE_DISCONNECT;
    }
    return result;
}

int IMakeCardSeaoryAdaptor::Reset()
{
    if (isOpen == false) {
        MAKECARD_HILOGE(MAKECARD_SRV, "device was not open");
        return ERR_DEVICE_NOT_OPEN;
    }
    int result = GetStatus();
    if (result == ERR_DEVICE_NOT_EXIST) {
        return ERR_DEVICE_DISCONNECT;
    }
    if (result == ERR_DEVICE_BUSY) {
        return result;
    }
    uint32_t libResult = SOY_PR_ExecCommand(usbPort, CMD_RESET_PRINTER_JAM);
    result = TransformResultCode("Reset jam", libResult);
    return result;
}

/**
 * 设置打印机配置
 */
int IMakeCardSeaoryAdaptor::SetConfig(int configType, int configValue)
{
    if (isOpen == false) {
        MAKECARD_HILOGE(MAKECARD_SRV, "device was not open");
        return ERR_DEVICE_NOT_OPEN;
    }
    int result = GetStatus();
    if (result == ERR_DEVICE_NOT_EXIST) {
        return ERR_DEVICE_DISCONNECT;
    }
    if (result == ERR_DEVICE_BUSY) {
        return result;
    }
    uint32_t libResult = SOY_PR_SetPrinterConfig(usbPort,
                                                (uint32_t)configType,
                                                (uint32_t)configValue);
    result = TransformResultCode("set config", libResult);
    return result;
}

/**
 * 设置standby参数
 */
int IMakeCardSeaoryAdaptor::SetStandbyParam(int dir, int pos, int standbyTime)
{
    if (isOpen == false) {
        MAKECARD_HILOGE(MAKECARD_SRV, "device was not open");
        return ERR_DEVICE_NOT_OPEN;
    }
    int result = GetStatus();
    if (result == ERR_DEVICE_NOT_EXIST) {
        return ERR_DEVICE_DISCONNECT;
    }
    if (result == ERR_DEVICE_BUSY) {
        return result;
    }
    uint32_t libResult = SOY_PR_SetStandbyParameters(usbPort, dir, pos, standbyTime);
    result = TransformResultCode("Set Standby Param", libResult);
    return result;
}

/**
 * 打印卡片
 */
int IMakeCardSeaoryAdaptor::PrintCard(BmpInfo cardBmpInfo)
{
    if (isOpen == false) {
        MAKECARD_HILOGW(MAKECARD_SRV, "device was not open");
        return ERR_DEVICE_NOT_OPEN;
    }
    MAKECARD_HILOGD(MAKECARD_SRV, "cardbmpinfo is %{public}s,%{public}s,%{public}s,%{public}s,%{public}s",
                    cardBmpInfo.lpFrontBGR, cardBmpInfo.lpFrontK, cardBmpInfo.lpFrontO,
                    cardBmpInfo.lpBackBGR, cardBmpInfo.lpBackK);
    int result = ERROR;
    uint32_t libResult = 1;
    BITMAP bmp24 = {0};
    BITMAP bmpK = {0};
    BITMAP bmpO = {0};
    BITMAP bmp24B = {0};
    BITMAP bmpKB = {0};
    BITMAP bmpOB = {0};

    int nWidth = 1012;
    int nHeight = 648;
    char szModel[32] = {0};
    bool bRxxx = false;
    PRINT_CARD_PARAM JobPara;

    InitCardParam(JobPara);
    JobPara.lpFrontBGR = &bmp24;
    JobPara.lpFrontK = &bmpK;
    JobPara.lpFrontO = &bmpO;
    JobPara.lpBackBGR = &bmp24B;
    JobPara.lpBackK = &bmpKB;
    JobPara.lpBackO = &bmpOB;
    //  1. 获取打印机状态
    result = GetStatus();
    if (result == ERR_DEVICE_NOT_EXIST) {
        return ERR_DEVICE_DISCONNECT;
    }

    CheckCall(SOY_PR_GetPrinterInfo(usbPort, INFO_MODEL_NAME, szModel));
    if (strcmp(szModel, "R600") == 0 || strcmp(szModel, "R600M") == 0 ||
        strcmp(szModel, "DCE905") == 0 || strcmp(szModel, "DR600") == 0 ||
        strcmp(szModel, "D600") == 0 ) {
        nWidth = 2060;
        nHeight = 1296;
        bRxxx = true;
    } else if (strcmp(szModel, "R300") == 0) {
        nWidth = 1030, nHeight = 648;
        bRxxx = true;
    }

    memset_s(&bmp24, sizeof(BITMAP), 0, sizeof(BITMAP));
    memset_s(&bmpK, sizeof(BITMAP), 0, sizeof(BITMAP));
    memset_s(&bmpO, sizeof(BITMAP), 0, sizeof(BITMAP));
    memset_s(&bmp24B, sizeof(BITMAP), 0, sizeof(BITMAP));
    memset_s(&bmpKB, sizeof(BITMAP), 0, sizeof(BITMAP));
    memset_s(&bmpOB, sizeof(BITMAP), 0, sizeof(BITMAP));

    char szCardPos[32] = {0};
    int nCardPos = 0;
    char szRibbonCount[32] = {0};
    int nRibbonCount = 0;

    //  判断打印机内是否有卡
    libResult = SOY_PR_GetPrinterInfoA(usbPort, INFO_CARD_POSITION, szCardPos);
    MAKECARD_HILOGD(MAKECARD_SRV, "SOY_PR_GetPrinterInfoA(INFO_CARD_POSITION) => %s\n", szCardPos);
    nCardPos = atoi(szCardPos);
    if (nCardPos == 0) {
        return ERR_NO_CARD;
    }

    // 2. 判断色带是否足量
    libResult = SOY_PR_GetPrinterInfoA(usbPort, INFO_RIBBON_COUNT, szRibbonCount);
    MAKECARD_HILOGD(MAKECARD_SRV, "SOY_PR_GetPrinterInfoA(INFO_RIBBON_COUNT) => %s\n", szRibbonCount);
    nRibbonCount = atoi(szRibbonCount);

    // 2.a 色带不足量，流程结束
    if ( nRibbonCount < 1 ) {
        return ERR_RIBBON_OUT;  // Ribbon out (41)
    }

    if ((cardBmpInfo.direction & 0x00000001) == 0x00000001) {
        CheckCall(ReadBmpFile((char*)cardBmpInfo.lpFrontBGR, &bmp24));
        CheckCall(ReadBmpFile((char*)cardBmpInfo.lpFrontK, &bmpK));

        if (!bRxxx) {
            CheckCall(ReadBmpFile((char*)cardBmpInfo.lpFrontO, &bmpO));
        }
    }

    if ((cardBmpInfo.direction & 0x00000010) == 0x00000010) {
        CheckCall(ReadBmpFile((char*)cardBmpInfo.lpBackBGR, &bmp24B));
        CheckCall(ReadBmpFile((char*)cardBmpInfo.lpBackK, &bmpKB));
        if (!bRxxx) {
            CheckCall(ReadBmpFile((char*)cardBmpInfo.lpBackO, &bmpOB));
        }
    }

    libResult = SOY_PR_PrintOneCard(usbPort, &JobPara);
    result = TransformResultCode("Print Card", libResult);
    MAKECARD_HILOGD(MAKECARD_SRV, "IMakeCardSeaoryAdaptor::PrintCard out");
    FreeCardParam(JobPara);
    return result;
}

/**
 * 获取打印机信息
 */
int IMakeCardSeaoryAdaptor::GetDeviceInfo(int infoType, char *infoValue)
{
    if (isOpen == false) {
        MAKECARD_HILOGE(MAKECARD_SRV, "device was not open");
        return ERR_DEVICE_NOT_OPEN;
    }
    if (infoValue == nullptr) {
        MAKECARD_HILOGE(MAKECARD_SRV, "param infoValue buffer was null");
        return ERR_TRANS_PARAM_ERROR;
    }
    int result = GetStatus();
    if (result == ERR_DEVICE_NOT_EXIST) {
        return ERR_DEVICE_DISCONNECT;
    }
    if (result == ERR_DEVICE_BUSY) {
        return result;
    }
    uint32_t libResult = SOY_PR_GetPrinterInfo(usbPort, infoType, infoValue);
    result = TransformResultCode("Get Device Info", libResult);
    return result;
}

/**
 * 获取错误信息
 */
void IMakeCardSeaoryAdaptor::GetErrorString(uint32_t status, char *statusDesc)
{
    int32_t i = 0;

    if (statusDesc == nullptr) {
        MAKECARD_HILOGE(MAKECARD_SRV, "param statusDesc buffer was null");
        return;
    }

    if (status < 0x00010001) {
        while (ErrorMap2[i].dwErrCode != 0xFFFFFFFF) {
            if ((uint32_t)status == ErrorMap2[i].dwErrCode) {
                strcpy_s(statusDesc, 256, ErrorMap2[i].pDesc);
                break;
            }
            i++;
        }
        return;
    }

    while (ErrorMap[i].dwErrCode != 0xFFFFFFFF) {
        if ((uint32_t)status == ErrorMap[i].dwErrCode) {
            strcpy_s(statusDesc, 256, ErrorMap[i].pDesc);
            break;
        }
        i++;
    }
    return;
}

/**
 * 转换sdk中的结果码为制卡机标准结果码
 */
int IMakeCardSeaoryAdaptor::TransformResultCode(string func, uint32_t libResult)
{
    int result = ERROR;
    char statusDesc[256] = {0};
    GetErrorString(libResult, statusDesc);
    MAKECARD_HILOGD(MAKECARD_SRV, "%{public}s result description is %{public}s", func.c_str(), statusDesc);
    do {
        if (libResult == 0) {
            result = SUCCESS;
            break;
        }
        if ((libResult <= 0x0001001B) && (libResult >= 0x00010010)) {
            result = ERR_CARD_JAM;
            break;
        }
        if (libResult == 0x00010022) {
            result = ERR_REJECT_BOX_OPEN;
            break;
        }
        if (libResult == 0x00010023) {
            result = ERR_REJECT_BOX_FULL;
            break;
        }
        if (libResult == 0x00010033) {
            result = ERR_FLIPPER_ERROR;
            break;
        }
        if (libResult == 0x00011007) {
            result = ERR_FLIPPER_NOT_ATTACHED;
            break;
        }
        if (libResult == 0x00011005) {
            result = ERR_MAGNETIC_ENCODING_MODULE_NOT_ATTACHED;
            break;
        }
        if ((libResult >= 0x00010041) && (libResult <= 0x0001004A)) {
            if ((libResult == 0x00010043) || (libResult == 0x00010045)) {
                result = ERR_RIBBON_MISSING;
                break;
            }
            if ((libResult == 0x00010041) || (libResult == 0x00010046)) {
                result = ERR_RIBBON_OUT;
                break;
            }
            result = ERR_RIBBON_ERROR;
            break;
        }
        if ((libResult >= 0x00010051) && (libResult <= 0x00010053)) {
            result = ERR_CARD_FEED_ERROR;
            break;
        }
        if (libResult == 0x0001005E) {
            result = ERR_CARD_EJECT_ERROR;
            break;
        }
        if (libResult == 87) {
            result = ERR_TRANS_PARAM_ERROR;
            break;
        }
        if ((libResult == 170) || (libResult == 329)) {
            result = ERR_DEVICE_BUSY;
            break;
        }
        if (libResult == 1167) {
            result = ERR_DEVICE_NOT_EXIST;
            break;
        }
        if (libResult == 0x00011014) {
            result = ERR_NO_CARD;
            break;
        }
        if (libResult == 0x0001005F) {
            result = ERR_CARD_OUT;
            break;
        }
        if (libResult == 0x00010021) {
            result = ERR_COVER_OPEN;
            break;
        }
        if (libResult == 50) {
            result = ERR_REQUEST_NOT_SUPPORTED;
            break;
        }
        if (libResult == 0x000100A1) {
            result = ERR_THE_FIRMWARE_COMMAND_NOT_SUPPORTED;
            break;
        }
        if (libResult == 110) {
            result = ERR_OPEN_SPECIFIED_DEVICE_OR_FILE_FAILED;
            break;
        }
        if ((libResult >= 0x00010071) && (libResult <= 0x0001007A)) {
            if ((libResult == 0x00010071) || (libResult == 0x00010076)) {
                result = ERR_FILM_OUT;
                break;
            }
            if ((libResult == 0x00010073) || (libResult == 0x00010075)) {
                result = ERR_FILM_MISSING;
                break;
            }
            result = ERR_FILM_ERROR;
            break;
        }
    } while (0);

    return result;
}

/**
 * 传动卡片到指定位置
 */
int IMakeCardSeaoryAdaptor::MoveCard(int postionMoveTo)
{
    if (isOpen == false) {
        MAKECARD_HILOGW(MAKECARD_SRV, "device was not open");
        return ERR_DEVICE_NOT_OPEN;
    }
    if ((postionMoveTo < CMD_MOVE_CARD_TO_HOPPER) ||
       (postionMoveTo > CMD_MOVE_CARD_TO_PREPARE)) {
        MAKECARD_HILOGW(MAKECARD_SRV, "param postionMoveTo was invalid");
        return ERR_TRANS_PARAM_ERROR;
    }

    //  1. 获取打印机状态
    char szCardPos[32] = {0};
    int nCardPos = 0;
    uint32_t libResult = 1;
    int result = 0;
    result = GetStatus();
    if (result == ERR_DEVICE_NOT_EXIST) {
        return ERR_DEVICE_DISCONNECT;
    }
    if (result == ERR_DEVICE_BUSY) {
        return result;
    }

    // 判断打印机内是否有卡
    libResult = SOY_PR_GetPrinterInfoA(usbPort, INFO_CARD_POSITION, szCardPos);
    MAKECARD_HILOGD(MAKECARD_SRV, "SOY_PR_GetPrinterInfoA(INFO_CARD_POSITION) => %s\n", szCardPos);
    nCardPos = atoi(szCardPos);
    // 卡机内无卡
    if (nCardPos == 0) {
        return ERR_NO_CARD;
    }

    libResult = SOY_PR_ExecCommand(usbPort, postionMoveTo);
    result = TransformResultCode("Get Device Info", libResult);
    return result;
}

/**
 * 翻转卡片
 */
int IMakeCardSeaoryAdaptor::FlipCard()
{
    if (isOpen == false) {
        MAKECARD_HILOGW(MAKECARD_SRV, "device was not open");
        return ERR_DEVICE_NOT_OPEN;
    }
    // 1. 获取打印机状态
    char szCardPos[32] = {0};
    int nCardPos = 0;
    uint32_t libResult = ERROR;
    int result = GetStatus();
    if (result == ERR_DEVICE_NOT_EXIST) {
        return ERR_DEVICE_DISCONNECT;
    }
    if (result == ERR_DEVICE_BUSY) {
        return result;
    }
    // 判断打印机内是否有卡
    libResult = SOY_PR_GetPrinterInfoA(usbPort, INFO_CARD_POSITION, szCardPos);
    MAKECARD_HILOGD(MAKECARD_SRV, "SOY_PR_GetPrinterInfoA(INFO_CARD_POSITION) => %s\n", szCardPos);
    nCardPos = atoi(szCardPos);
    // 卡机内无卡
    if (nCardPos == 0) {
        return ERR_NO_CARD;
    }

    libResult = SOY_PR_ExecCommand(usbPort, CMD_FLIP_CARD);
    result = TransformResultCode("Get Device Info", libResult);
    return result;
}
}
}

std::shared_ptr<SwanLink::Finance::IAdaptor> CreateAdaptor()
{
    return std::static_pointer_cast<SwanLink::Finance::IAdaptor>(
        make_shared<SwanLink::Finance::IMakeCardSeaoryAdaptor>());
}

SwanLink::Finance::Transport GetAccess(SwanLink::Finance::ACCESS_MODE mode, const char *dev)
{
    SwanLink::Finance::Transport trans;
    if (mode == SwanLink::Finance::AM_SERIAL) {
        trans.mode = mode;
        strcpy_s(trans.dev, MAX_DEV_NAME_LEN, dev);
        trans.timeout = 5000;  // sdk中并未指定，默认为5000
        trans.size = sizeof(trans);
    } else {
        trans.mode = mode;
        strcpy_s(trans.dev, MAX_DEV_NAME_LEN, dev);
        trans.size = sizeof(trans);
    }
    return trans;
}

static Plugin g_plugin = {
    .CreateAdaptor = CreateAdaptor,
    .GetAccess = GetAccess,
    .version = "1.0",
    .name = "MakeCard_Seaory",
    .desc = "Seaory Adaptor",
    };
PLUGIN_INIT(&g_plugin)
